package com.deepface.web.controller.faceLab;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deepface.common.config.DflConfig;
import com.deepface.common.core.page.TableDataInfo;
import com.deepface.common.utils.SecurityUtils;
import com.deepface.common.utils.StringUtils;

import com.deepface.common.utils.file.FileTypeUtils;
import com.deepface.common.utils.file.FileUploadUtils;
import com.deepface.common.utils.process.ProcessUtils;
import com.deepface.framework.web.domain.server.Sys;
import com.deepface.system.domain.SysFaceJob;
import com.deepface.system.domain.SysFaceJobGroup;
import com.deepface.system.domain.SysFileInfo;
import com.deepface.system.domain.po.DflJobPo;
import com.deepface.system.service.SysFaceJobService;
import com.deepface.system.service.SysFileInfoService;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Scanner;
import javax.swing.text.TabableView;
import lombok.NonNull;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.deepface.common.core.controller.BaseController;
import com.deepface.common.core.domain.AjaxResult;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

/**
 * 换脸任务Controller
 *
 * @author ljq
 * @date 2023-12-14
 */
@CrossOrigin
@RestController
@RequestMapping("/system/dfl")
public class SysFaceJobController extends BaseController {

  @Autowired
  private SysFaceJobService sysFaceJobService;

  @Autowired
  private SysFileInfoService sysFileInfoService;

  /**
   * 新建子任务
   *
   * @param sysFaceJob
   * @return
   */
  @PostMapping(value = "/createSysFaceJob")
  public AjaxResult createSysFaceJob(@RequestBody SysFaceJob sysFaceJob) {
    if (sysFaceJobService.insertSysFaceJob(sysFaceJob) == 0) {
      return AjaxResult.error("数据库插入失败");
    }
    //jobGroupId
    Long jobGroupId = sysFaceJob.getJobGroupId();
    //
    if (jobGroupId == null) {
      return AjaxResult.error("工作组有误");
    }
    //为用户构建本次工作inputDir和outputDir
    String inputDir =
        DflConfig.getRootFilePath() + SecurityUtils.getUserId().toString() + "/" + jobGroupId + "/";
    String outputDir =
        DflConfig.getRootFilePath() + SecurityUtils.getUserId().toString() + "/" + jobGroupId + "/";
    //系统为用户决定输入和输出目录
    sysFaceJob.setJobInputDir(inputDir);
    sysFaceJob.setJobOutputDir(outputDir);
    //更新数据库
    sysFaceJobService.updateById(sysFaceJob);
    HashMap<String, Long> data = new HashMap<>();
    data.put("faceJobGroupId", sysFaceJob.getJobGroupId());
    data.put("faceJobId", sysFaceJob.getJobId());
    return AjaxResult.success(data);
  }

  /**
   * 修改子任务
   *
   * @param sysFaceJob
   * @return
   */
  @PostMapping(value = "/alterSysFaceJob")
  public AjaxResult alterSysFaceJob(@RequestBody SysFaceJob sysFaceJob) {
    if (sysFaceJobService.updateSysFaceJob(sysFaceJob) == 0) {
      return AjaxResult.error("更新失败");
    }
    return AjaxResult.success("更新成功");
  }


  /**
   * 展示该用户的任务列表
   *
   * @return
   */
  @GetMapping(value = "/listSysFaceJobByUser")
  public TableDataInfo listSysFaceJob() {
    startPage();
    Long id = SecurityUtils.getUserId();
    List<SysFaceJob> list =
        sysFaceJobService.list(Wrappers.<SysFaceJob>lambdaQuery()
            .eq(SysFaceJob::getUserId, id).eq(SysFaceJob::getDelFlag, 0));
    return getDataTable(list);
  }

  /**
   * 查询某个jobGroup下的所有job
   *
   * @return
   */
  @GetMapping(value = "/listSysFaceJobByJobGroup")
  public TableDataInfo listSysFaceJob(@RequestParam("jobGroupId") Long jobGroupId) {
    startPage();
    List<SysFaceJob> list =
        sysFaceJobService.list(Wrappers.<SysFaceJob>lambdaQuery()
            .eq(SysFaceJob::getJobGroupId, jobGroupId).eq(SysFaceJob::getDelFlag, 0));
    return getDataTable(list);
  }

  /**
   * 查询某个jobGroup下的所有sort为多少的job
   *
   * @return
   */
  @GetMapping(value = "/listSysFaceJobByPlus")
  public TableDataInfo listSysFaceJobPlus(DflJobPo dto) {
    startPage();
    List<SysFaceJob> list =
        sysFaceJobService.list(Wrappers.<SysFaceJob>lambdaQuery()
            .eq(SysFaceJob::getJobGroupId, dto.getJobGroupId()).eq(SysFaceJob::getDelFlag, 0)
            .like(Objects.nonNull(dto.getJobSort()), SysFaceJob::getJobSort, dto.getJobSort())
            .like(Objects.nonNull(dto.getJobName()), SysFaceJob::getJobName, dto.getJobName())
        );
    return getDataTable(list);
  }

  /**
   * 删除子任务
   *
   * @return
   */
  @PostMapping(value = "/deleteSysFaceJob/{jobId}")
  public AjaxResult deleteSysFaceJob(@PathVariable("jobId") Long id) {
    SysFaceJob sysFaceJob = new SysFaceJob();
    sysFaceJob.setDelFlag("1");
    sysFaceJob.setJobId(id);
    Boolean res = sysFaceJobService.update(sysFaceJob, Wrappers.<SysFaceJob>lambdaUpdate()
        .eq(SysFaceJob::getDelFlag, "0").eq(SysFaceJob::getJobId, id));
    if (!res) {
      return AjaxResult.error("删除失败");
    } else {
      return AjaxResult.success("删除成功");
    }
  }

  /**
   * 针对子任务的视频文件上传，上传data_src和data_dst，通过fileNowName控制上传到src还是dst 并将文件上传记录写入相应的sys_file_info
   *
   * @param files
   * @param jobId
   * @param fileNowName
   * @return
   */
//  @PostMapping("/uploadFile")
//  public AjaxResult uploadFile(@RequestParam("file") MultipartFile[] files,
//      @RequestParam Long jobId, @RequestParam String fileNowName) {
//    if (files == null || files.length == 0) {
//      return AjaxResult.error("请至少选择一个文件进行上传");
//    }
//    Optional<SysFaceJob> optionalSysFaceJob = Optional.ofNullable(sysFaceJobService.getOne(
//        Wrappers.<SysFaceJob>lambdaQuery().eq(SysFaceJob::getJobId, jobId).eq(
//            SysFaceJob::getDelFlag, "0")));
//
//    if (!optionalSysFaceJob.isPresent()) {
//      return AjaxResult.error("所选任务已经失效，请重新选择");
//    }
//
//    String jobInputDir = optionalSysFaceJob.get().getJobInputDir();
//    if (StringUtils.isNotBlank(jobInputDir) == false) {
//      return AjaxResult.error("文件目标上传路径为空，请重新创建任务");
//    }
//
//    for (MultipartFile file : files) {
//      try {
//        String suffix = FileTypeUtils.getFileType(file.getOriginalFilename());
//        //文件上传
//        FileUploadUtils.upload(jobInputDir, file,
//            fileNowName + "." + suffix);
//        //sysFileInfo插入
//        sysFileInfoService.insertSysFileInfo(file, jobInputDir, fileNowName);
//      } catch (Exception e) {
//        return AjaxResult.error("文件上传有误" + e.getMessage());
//      }
//    }
//    return AjaxResult.success("成功上传文件");
//  }

  @PostMapping("/uploadFile")
  public AjaxResult uploadFile(@RequestParam("file") MultipartFile[] files,
      @RequestParam Long jobId, @RequestParam String fileNowName) {
    if (files == null || files.length == 0) {
      return AjaxResult.error("请至少选择一个文件进行上传");
    }
    Optional<SysFaceJob> optionalSysFaceJob = Optional.ofNullable(sysFaceJobService.getOne(
        Wrappers.<SysFaceJob>lambdaQuery().eq(SysFaceJob::getJobId, jobId).eq(
            SysFaceJob::getDelFlag, "0")));

    if (!optionalSysFaceJob.isPresent()) {
      return AjaxResult.error("所选任务已经失效，请重新选择");
    }

    String jobInputDir = optionalSysFaceJob.get().getJobInputDir();
    if (StringUtils.isNotBlank(jobInputDir) == false) {
      return AjaxResult.error("文件目标上传路径为空，请重新创建任务");
    }
    for (MultipartFile file : files) {
      try {
        String suffix = FileTypeUtils.getFileType(file.getOriginalFilename());
        //文件上传
        String targetURL = "http://123.57.18.66:5000/upload"; // Flask 服务器的地址
        URL url = new URL(targetURL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        String postData = "filePath=" + jobInputDir + fileNowName + "." + suffix;
        System.out.println("-------filePath---" + postData);
        try (OutputStream outputStream = connection.getOutputStream()) {
          outputStream.write(postData.getBytes());
          outputStream.flush();
        }
        //sysFileInfo插入
        sysFileInfoService.insertSysFileInfo(file, jobInputDir, fileNowName);

        // 读取服务器响应（如果需要的话）
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
          // 服务器成功接收文件
          System.out.println("File uploaded successfully to the server.");
        } else {
          // 服务器未能成功接收文件
          System.out.println("Failed to upload file to the server. Response code: " + responseCode);
        }

        connection.disconnect();
      } catch (Exception e) {
        return AjaxResult.error("文件上传有误" + e.getMessage());
      }
    }
    return AjaxResult.success("成功上传文件");
  }

  /**
   * 7个子任务启动（拼接命令）
   *
   * @param sysFaceJobPo
   * @return
   */
  @PostMapping("/StartJob")
  public AjaxResult startJob(@NonNull SysFaceJob sysFaceJobPo) {
    //cmd命令构造
    Long jobId = sysFaceJobPo.getJobId();

    //对应到数据库的job
    Optional<SysFaceJob> optionalSysFaceJob = Optional.ofNullable(sysFaceJobService.getOne(
        Wrappers.<SysFaceJob>lambdaQuery().eq(SysFaceJob::getJobId, jobId).eq(
            SysFaceJob::getDelFlag, "0")));

    if (!optionalSysFaceJob.isPresent()) {
      return AjaxResult.error("所选任务已经失效，请重新选择");
    }
    // bean copy
    SysFaceJob sysFaceJob = optionalSysFaceJob.get();
    CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true);
    BeanUtil.copyProperties(sysFaceJobPo, sysFaceJob, copyOptions);

    //
    String command = DflConfig.getRootWorkPath() + sysFaceJob.getCommand();

    //构建上传目录
    String inputDir = sysFaceJob.getJobInputDir();
    String outputDir = sysFaceJob.getJobOutputDir();

    //todo:检查上传目录内容是否存在

    //
    Integer step = sysFaceJob.getJobSort();
    System.out.println(step);

    //根据不同步骤需要的参数构造命令
    Process process = null;
    if (step == 1 || step == 2) {
      System.out.println(
          command + " " + inputDir + " " + outputDir + " " + sysFaceJob.getOutputExt() + " "
              + sysFaceJob.getFps().toString());
      process = ProcessUtils.start(command, inputDir, outputDir,
          sysFaceJob.getOutputExt(), sysFaceJob.getFps().toString());
    } else if (step == 3 || step == 4) {
      System.out.println(command + " " + inputDir + " " + outputDir + " " +
          sysFaceJob.getFaceType() + " " + sysFaceJob.getMaxFaceFromImage().toString() + " " +
          sysFaceJob.getImageSize().toString() + " " + sysFaceJob.getJpegQuality().toString() + " "
          +
          sysFaceJob.getForceGpuIdxs().toString() + " ");

      process = ProcessUtils.start(command, inputDir, outputDir,
          sysFaceJob.getFaceType(), sysFaceJob.getMaxFaceFromImage().toString(),
          sysFaceJob.getImageSize().toString(), sysFaceJob.getJpegQuality().toString(),
          sysFaceJob.getForceGpuIdxs().toString());

      handleUserInput(process);
      handleProcessOutput(process);

    } else if (step == 5) {
      process = ProcessUtils.start(command, inputDir, outputDir,
          sysFaceJob.getForceGpuIdxs().toString(), sysFaceJob.getMaxIterations().toString(),
          sysFaceJob.getForceModelName());
    } else if (step == 6) {
      process = ProcessUtils.start(command, inputDir, outputDir,
          sysFaceJob.getForceGpuIdxs().toString(), sysFaceJob.getForceModelName(),
          sysFaceJob.getErodeMaskModifier().toString(), sysFaceJob.getBlurMaskModifier().toString(),
          sysFaceJob.getSuperResolutionPower().toString(),
          sysFaceJob.getSubprocessCount().toString());
    } else if (step == 7) {
      process = ProcessUtils.start(command, inputDir, outputDir);
    } else {
      return AjaxResult.error();
    }
    System.out.println("ok");

    //回写进程pid
    Long jobPid = ProcessUtils.getPid(process);
    sysFaceJob.setJobPid(jobPid);
    sysFaceJob.setState(1);
    sysFaceJobService.update(sysFaceJob,
        Wrappers.<SysFaceJob>lambdaUpdate().eq(SysFaceJob::getJobId, jobId)
            .eq(SysFaceJob::getDelFlag, "0"));

    return AjaxResult.success("成功发送执行命令");
  }


  @PostMapping("/startJobFarAway")
  public AjaxResult startJobFarAway(@RequestBody SysFaceJob sysFaceJobPo) {
    //cmd命令构造
    Long jobId = sysFaceJobPo.getJobId();

    //对应到数据库的job
    Optional<SysFaceJob> optionalSysFaceJob = Optional.ofNullable(sysFaceJobService.getOne(
        Wrappers.<SysFaceJob>lambdaQuery().eq(SysFaceJob::getJobId, jobId).eq(
            SysFaceJob::getDelFlag, "0")));

    if (!optionalSysFaceJob.isPresent()) {
      return AjaxResult.error("所选任务已经失效，请重新选择");
    }

    // bean copy
    SysFaceJob sysFaceJob = optionalSysFaceJob.get();
    CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true);
    BeanUtil.copyProperties(sysFaceJobPo, sysFaceJob, copyOptions);

    //
    String command = DflConfig.getRootWorkPath() + sysFaceJob.getCommand();

    //构建上传目录
    String inputDir = sysFaceJob.getJobInputDir();
    String outputDir = sysFaceJob.getJobOutputDir();

    //todo:检查上传目录内容是否存在

    //
    Integer step = sysFaceJob.getJobSort();
    System.out.println(step);

    String apiUrl = DflConfig.getApiUrl();
    System.out.println(apiUrl);
    RestTemplate restTemplate = new RestTemplate();
    Map<String, String> commandParameters = new HashMap<>();
    commandParameters.put("jobId", sysFaceJob.getJobId().toString());
    commandParameters.put("jobSort", sysFaceJob.getJobSort().toString());
    commandParameters.put("command", command);
    commandParameters.put("inputDir", inputDir);
    commandParameters.put("outputDir", outputDir);
    commandParameters.put("outputExt", sysFaceJob.getOutputExt());
    commandParameters.put("fps", sysFaceJob.getFps().toString());
    commandParameters.put("faceType", sysFaceJob.getFaceType());
    commandParameters.put("maxFaceFromImage", sysFaceJob.getMaxFaceFromImage().toString());
    commandParameters.put("imageSize", sysFaceJob.getImageSize().toString());
    commandParameters.put("jpegQuality", sysFaceJob.getJpegQuality().toString());
    commandParameters.put("forceGpuIdxs", sysFaceJob.getForceGpuIdxs().toString());
    commandParameters.put("forceMoudelName", sysFaceJob.getForceModelName());
    commandParameters.put("maxIterations", sysFaceJob.getMaxIterations().toString());
    commandParameters.put("erodeMaskModifier", sysFaceJob.getErodeMaskModifier().toString());
    commandParameters.put("blurMaskModifier", sysFaceJob.getBlurMaskModifier().toString());
    commandParameters.put("superResolutionPower", sysFaceJob.getSuperResolutionPower().toString());
    commandParameters.put("subprocessCount", sysFaceJob.getSubprocessCount().toString());

    Map<String, Object> response = restTemplate.postForObject(apiUrl, commandParameters, Map.class);
    System.out.println("远程命令执行的响应: " + (String) response.get("message"));

    //回写进程pid
    //    Long jobPid = ProcessUtils.getPid(process);
//    sysFaceJob.setJobPid(jobPid);
//    sysFaceJob.setState(1);
//    sysFaceJobService.update(sysFaceJob,
//        Wrappers.<SysFaceJob>lambdaUpdate().eq(SysFaceJob::getJobId, jobId)
//            .eq(SysFaceJob::getDelFlag, "0"));

    return AjaxResult.success("成功发送执行命令");
  }

  /**
   * 任务中止
   *
   * @param pid
   * @return
   */
  @GetMapping(value = "/stop")
  public AjaxResult stop_process(@RequestParam long pid) {
    ProcessUtils.stop(pid);
    return AjaxResult.success("成功发送执行命令");
  }

  private void handleProcessOutput(Process processa) {
    if (processa == null) {
      System.err.println("Process对象为空！");
      return;
    }
    new Thread(() -> {
      try (BufferedReader reader = new BufferedReader(
          new InputStreamReader(processa.getInputStream()))) {
        String line;
        while ((line = reader.readLine()) != null) {
          System.out.println(line);
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }).start();
  }

  private void handleUserInput(Process process) {
    new Thread(() -> {
      try (BufferedWriter writer = new BufferedWriter(
          new OutputStreamWriter(process.getOutputStream()));
          Scanner scanner = new Scanner(System.in)) {
        while (true) {
          System.out.println("Enter input for the process (type 'exit' to stop): ");
          String input = scanner.nextLine();
          if ("exit".equalsIgnoreCase(input)) {
            break; // Exit the loop, effectively stopping the input
          }
          writer.write(input);
          writer.newLine();
          writer.flush();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }).start();
  }


}
